#!/usr/bin/env node
const path = require("path")
const fs = require("fs")
const program = require('commander');

const ALL_CONFIG = require("./project.conf")
const { genPageContent, updateByApi } = require("./runapi")
const { updateByApiParams } = require("./runapi/model");
const dayjs = require("dayjs");
const api_key = "c178f5a89c1453ccccf371772d497b2d1971588260"
const api_token = "83c1c6cf61bc790db285eb6b547f851a1930882790"
const cache = {}


const TARS_PATH = path.resolve(__dirname, "./protocol/Open.tars")
let NUMBER = 1
/**objDesMap {
 * validPermissionRsp: {
    status: { tag: '0', require: 'require', type: 'int', des: ' 状态' },
    data: { tag: '1', require: 'optional', type: 'string', des: '数据' },
    message: { tag: '2', require: 'optional', type: 'string', des: ' 消息' }
  }
}
 */

var tarsTypeMap = {
  bool: false,
  byte: 0,
  short: 0,
  int: 0,
  long: 0,
  float: 0,
  double: 0,
  string: "",
  vector: []
}
var vectorReg = /vector<(\w+)>/
const moduleReg = /module\s+(\w*)+\s+{([\s\S]*)interface/
const interfaceReg = /interface\s+(\w*)+\s*{([\s\S]*?)}/
const structReg = /struct\s+(.*?)\s*{([\s\S]*?)}/g
let moduleName = 'test'
let interfaceName = 'interface'

// parse(TARS_PATH)

program.version('0.0.1');
program
  .option('-d,--d', ' params: projectname  dirpath  baseurl ')
  .option('-f,--f', ' params: projectname  filepath baseurl title')

program.parse(process.argv)

if (program.args.length < 2) {
  console.error("缺少参数")
} else if (program.d) {
  let commonConfig = ALL_CONFIG[program.args[0]]
  commonConfig.base_url = program.args[2] ? program.args[2] : commonConfig.base_url
  let dirpath = /^\//.test(program.args[1]) ? program.args[1] : path.resolve(__dirname, program.args[1])
  let files = fs.readdirSync(dirpath)
  files = files.filter(f=>{
    let suf = f.split(".")[1]
    return suf == "tars"
  })
  console.log("files",files)
  let { exclude = [], include = [] } = commonConfig

  for (const file of files) {
    const filepath = path.resolve(dirpath, file)
    let filename = file.split(".")[0].toLocaleLowerCase()
    let pageConfig = commonConfig.tars[filename]
    if (include.length > 0 ) {
      if(include.includes(filename)){
        parse(filepath, {tarsname:filename, commonConfig, pageConfig })
      }
      
    }else if (exclude.length > 0 ){
      if(!exclude.includes(filename)){
        parse(filepath, {tarsname:filename, commonConfig, pageConfig })
      } 
    }else{
      parse(filepath, {tarsname:filename, commonConfig, pageConfig })
    }
  }
  console.log("success!")
} else if (program.f) {
  let commonConfig = ALL_CONFIG[program.args[0]]
  commonConfig.base_url = program.args[2] ? program.args[2] : commonConfig.base_url

  let filepath = /^\//.test(program.args[1]) ? program.args[1] : path.resolve(__dirname, program.args[1])
  let filename = path.basename(filepath).split(".")[0]
  let pageConfig = commonConfig.tars[filename.toLowerCase()]
  pageConfig.title = program.args[3] ? program.args[3] : pageConfig.title
  parse(filepath, { commonConfig, pageConfig })
  console.log("success!")

}

async function parse(location, {tarsname, commonConfig, pageConfig }) {

  /**
   * 数据重置 避免多个tars解析后污染
   */
  var objDesMap = {}  // 存放原始解析数据
  var objMap = {}    // 存放普通对象 方便生成示例数据
  var interfaceSourceObj = {}
  var interfaceList = []
  let vectorList = []
  let customTypeList = []


  let text = fs.readFileSync(location).toString();

  if (!text) {
    console.error("内容为空")
  }
  // console.log(text)
  text = text.trim()
  // 匹配模块名和所有的struct信息
  let match = text.match(moduleReg)
  moduleName = match[1]
  let structInfo = match[2]
  // console.log("结构体信息::", structInfo)
  // 匹配接口名和所有的接口信息
  match = text.match(interfaceReg)
  let interfaceInfo = match[2]
  interfaceName = match[1]
  console.log("模块和接口名", moduleName, interfaceName)


  console.log("接口信息::", interfaceInfo)
  // 循环解析单个structInfo
  match = structInfo.replace(structReg, function (value, $1, $2) {
    // 提取struct名字及其内容 生成类型对象及参数对象
    parseStructInfo($1, $2, objDesMap)
    return value
  })

  objMap = genObj(objDesMap)

  // console.log("objmap", objMap)






  // 解析完所有类型后  解析接口信息
  parseInterfaceInfo(interfaceInfo, interfaceSourceObj, interfaceList)
  // console.log("objmap", JSON.stringify(objMap))
  // console.log('objdesmap', JSON.stringify(objDesMap))
  // console.log("vectorList", vectorList)
  // console.log("customTypeList", customTypeList)
  // console.log("interfaceSourceObj", interfaceSourceObj)
  // console.log("interfaceList", interfaceList)
  let backup = ''
  let secondTime = dayjs().format("YYYYMMDDHHmmss")
  let filepath = path.resolve(__dirname,"./backup/" +tarsname + "_" + secondTime)


  for (const item of interfaceList) {
    let { exclude = [], include = [] } = pageConfig
    if (include.length > 0) {
      if(!include.includes(item.fn)){
        continue
      }
    } else if(exclude.length > 0) {
      if ( exclude.includes(item.fn)) {
        continue
      }
    }

    const pageContent = genPageContent({ interfaceItem: item, objMap, objDesMap, commonConfig, pageConfig })
    let params = new updateByApiParams()
    params.api_key = commonConfig.api_key
    params.api_token = commonConfig.api_token
    params.cat_name = pageConfig.title
    params.page_title = item.des
    params.page_content = JSON.stringify(pageContent)
    params.s_number = NUMBER++
    // let v = cache[params.cat_name + "/" + params.page_title]
    // if (v) {
    //   if (v.pageContent === params.content &&
    //     v.sNumber === params.s_number &&
    //     v.api_key === params.api_key &&
    //     v.api_token === params.api_token) {
    //     console.log(`${moduleName}模块下的${interfaceName}接口下的${item.fn}方法未发生变化`)
    //     continue
    //   }
    // }
    const res = await updateByApi(params)
    cache[params.cat_name + "/" + params.page_title] = {
      pageContent: params.page_content,
      sNumber: params.s_number,
      api_key,
      api_token
    }
    console.log("请求成功 ",item.fn, res.data.error_code)
    backup += `\n## ${params.cat_name}/${params.page_title}\n${JSON.stringify(params)}\n`
  }

  fs.writeFileSync(filepath,backup)
  console.log("备份完成",filepath)
}


function parseStructInfo(name, detail, objDesMap) {
  detail = detail.replace(/^\s+|\s+$/, '')  // 去除前后换行

  list = detail.split(/\r\n|\r|\n/)
  for (var line of list) {
    line = line.trim()
    let info = line.split("//")

    if (/^\/\//.test(line) || !line || (/^\s+$/.test(line))) {
      continue
    }
    let field = info[0]
    let des = info[1]
    // 去除首尾空格
    field = field.trim()
    // 去除结尾分号
    field = field.slice(0, field.length - 1)
    field = field.split(/\s+/)

    let tag = field[0]
    let require = field[1]
    let type = field[2]
    let property = field[3]
    if (!objDesMap[name]) {
      objDesMap[name] = {}
    }

    objDesMap[name][property] = {
      key: property,
      tag,
      require,
      type,
      des: des,  // 注释不能有空格

    }
  }
}

function parseInterfaceInfo(interfaceInfo, interfaceSourceObj, interfaceList) {
  // 默认最多只有两个参数
  interfaceInfo = interfaceInfo.replace(/^\s+|\s+$/, '') // 去除前后换行
  list = interfaceInfo.split(";")
  for (let line of list) {
    line = line.replace(/^\s+|\s+$/, '')
    if (!line) {
      continue
    }
    let info = line.split(/\r\n|\r|\n/)
    let des
    let funcInfo
    if(info.length == 2){
      des = info[0].replace(/\s*\/\/\s*/, '')
      funcInfo =  info[1]
    }else {
      des = ''
      funcInfo = info[0]
    }
    var m = funcInfo.match(/(\w*?)\s+(\w*?)[(](.*?)[)]/)

    let rsp = m[1]
    let fn = m[2]
    let params = m[3]
    params = params.split(',')
    if (tarsTypeMap.hasOwnProperty(rsp)) {
      let out = params[1]
      out = out.trim().split(/\s+/)
      rsp = out[1]
    }
    let req = params[0].trim().split(/\s+/)[0]
    interfaceSourceObj[fn] = funcInfo
    interfaceList.push({ fn, req, rsp, des })
  }
}

function genObj(data) {
  let obj = Object.create(null)
  let keys = Object.keys(data)
  keys.forEach(k => {
    obj[k] = help(data, k)
  })
  return obj
}

function isRawType(type) {
  return tarsTypeMap.hasOwnProperty(type)
}
function getVectorType(type) {
  return type.match(vectorReg)
}

function help(data, k, isArray) {
  let result = {}
  let source = data[k]
  for (const key in source) {
    if (Object.hasOwnProperty.call(source, key)) {
      const el = source[key];
      if (isRawType(el.type)) {
        result[key] = tarsTypeMap[el.type]
      } else {
        let v = getVectorType(el.type)
        if (v) {
          if (isRawType(v[1])) {
            result[key] = [tarsTypeMap[v[1]]]
          } else {
            result[key] = help(data, v[1], true)
          }
        } else {
          result[key] = help(data, el.type)
        }
      }
    }
  }

  return isArray ? [result] : result
}